
require "LevelHelper.Helpers.LHHelpers"
require "LevelHelper.Helpers.LHObject"
require "LevelHelper.Helpers.LHArray"
require "LevelHelper.Helpers.LHDictionary"

require "LevelHelper.Nodes.LHSettings"
--------------------------------------------------------------------------------
--forward declaration of local functions

LHBezier = Core.class(Sprite)
function LHBezier:bezierWithDictionary(fullProperties) --returns a display object

	--local bezierObj = self;--display.newGroup();
	local properties	 = fullProperties:dictForKey("TextureProperties");
	
	self.lhIsClosed	 = properties:boolForKey("IsClosed")
	self.lhUniqueName	 = properties:stringForKey("UniqueName")
	self.lhIsTile		 = properties:boolForKey("IsTile")
	self.lhIsLine		 = properties:boolForKey("IsSimpleLine")
	self:setVisible(properties:boolForKey("IsDrawable"));
	
	self.lhIsPath		 = properties:boolForKey("IsPath")
	self.lhPathPoints	 = {};
	self.lhTag			 = properties:intForKey("Tag")
	
	self.lhColor		 = properties:rectForKey("Color")
	self.lhLineWidth	 = properties:floatForKey("LineWidth")
	self.lhLineColor	 = properties:rectForKey("LineColor")
	self.lhDrawBorder	 = properties:boolForKey("DrawBorder");
	
	self.lhZOrder		 = properties:intForKey("ZOrder");
	self.lhNodeType	 = "LHBezier"
	self.lhOpacity		 = properties:floatForKey("Opacity");
	
	self:setUserClassProperties(fullProperties);
	
	self:createRenderVerticesFromDictionary(fullProperties)
	self:constructPathPoints(properties)	
	self:constructPhysicObjectFromDictionary(fullProperties)
	
	--overloaded functions
	----------------------------------------------------------------------------
	self:addEventListener(Event.ENTER_FRAME, self.enterFrame, self)
	
	
	return self; --displayObject of corona
end
--------------------------------------------------------------------------------
function LHBezier:enterFrame(event)

	if(self.body)then
		self:setPosition(self.body:getPosition())
		self:setRotation(self.body:getAngle() * 180 / math.pi)
	end
end
--------------------------------------------------------------------------------
function LHBezier:uniqueName()
	return self.lhUniqueName;
end
--------------------------------------------------------------------------------
function LHBezier:userCustomInfoClassName()
	return self.lhClassName   
end
--------------------------------------------------------------------------------
function LHBezier:userCustomInfo()
	 return self.lhUserCustomInfo;
end
--------------------------------------------------------------------------------
function LHBezier:removeSelf()
	print("calling LHBezier removeSelf " .. self.lhUniqueName .. " parent " .. self:getParent().lhUniqueName);
	--remove all properties of this sprite here
	
	self:removeEventListener(Event.ENTER_FRAME, self.enterFrame, self);
	
	
	self.lhIsClosed	 = nil
	self.lhUniqueName = nil
	self.lhIsTile	 = nil
	self.lhIsLine	 = nil
	self.lhIsPath	 = nil	
	for i = 1, #self.lhPathPoints do
		self.lhPathPoints[i].x = nil
		self.lhPathPoints[i].y = nil
	end
	self.lhPathPoints = nil
	self.lhTag		 = nil
	self.lhColor		 = nil
	self.lhLineWidth	 = nil
	self.lhLineColor	 = nil
	self.lhZOrder	 = nil
	self.lhNodeType	 = nil

	if(self.b2World)then
		if(self.body)then
			self.b2World:destroyBody(self.body);
		end
	end
	self.b2World = nil;
	self:removeFromParent();
end
--------------------------------------------------------------------------------
pointOnCurve = function(p1, p2, p3, p4, t)
	local var1
	local var2
	local var3
	local vPoint = {x = 0.0, y = 0.0}
	
	var1 = 1 - t
	var2 = var1 * var1 * var1
	var3 = t * t * t
	vPoint.x = var2*p1.x + 3*t*var1*var1*p2.x + 3*t*t*var1*p3.x + var3*p4.x
	vPoint.y = var2*p1.y + 3*t*var1*var1*p2.y + 3*t*t*var1*p3.y + var3*p4.y

	return vPoint;
end
--------------------------------------------------------------------------------
function LHBezier:constructPathPoints(bezierDict)

	if false == self.lhIsPath then
		return
	end

	local convert = {x = 1.0, y = 1.0};

	local curves = bezierDict:arrayForKey("Curves")
	local MAX_STEPS = 25;

	for i= 1, curves:count() do
		
		local curve = curves:dictAtIndex(i)
		local endCtrlPt   = curve:pointForKey("EndControlPoint")
		local startCtrlPt = curve:pointForKey("StartControlPoint")
		local endPt	   = curve:pointForKey("EndPoint")
		local startPt	 = curve:pointForKey("StartPoint")

		  if false == self.lhIsLine then
			local t = 0.0
			while ( t >= 0.0 and  t <= 1 + (1.0 / MAX_STEPS) ) do
				local vPoint = pointOnCurve(startPt, startCtrlPt, endCtrlPt, endPt, t)
							
				self.lhPathPoints[#self.lhPathPoints+1] = {	x = vPoint.x*convert.x, 
																		y = vPoint.y*convert.y}
						
				t = t + 1.0 / MAX_STEPS
			end
			
			table.remove(self.lhPathPoints,#self.lhPathPoints)
		  else

			self.lhPathPoints[#self.lhPathPoints+1] = {	 x = startPt.x*convert.x,
																	y = startPt.y*convert.y}
			if(i == curves:count())then
				self.lhPathPoints[#self.lhPathPoints+1] = {	 x = endPt.x*convert.x, 
																		y = endPt.y*convert.y}
			end
		  end						 
	end
end
--------------------------------------------------------------------------------
function LHBezier:createLineShape(pt1, pt2, color)

	local r = lh_toInt(color.origin.x*255)
	local g = lh_toInt(color.origin.y*255);
	local b = lh_toInt(color.size.width*255);
	local hexColorStr = string.format("%02X%02X%02X", r,g,b)
	local hexcolor = tonumber(hexColorStr, 16)					 
	
	local lineOpacity = 1;
	
	if(self.lhDrawBorder == false)then
		lineOpacity = 0;
	end
	
	local shape = Shape.new()
	shape:setLineStyle(4, hexcolor, lineOpacity)

	shape:beginPath()
	shape:moveTo(pt1.x, pt1.y)
	shape:lineTo(pt2.x, pt2.y)
	shape:closePath()
	shape:endPath()
	
	self:addChild(shape);
end
--------------------------------------------------------------------------------
function LHBezier:createRenderVerticesFromDictionary(fullProperties)
	 
	local texDict = fullProperties:dictForKey("TextureProperties");
	
	
	local convert = {x = 1.0, y = 1.0};
	--local winSize = {width = 320, height = 480};	

	local r = lh_toInt(self.lhColor.origin.x*255)
	local g = lh_toInt(self.lhColor.origin.y*255);
	local b = lh_toInt(self.lhColor.size.width*255);
	local hexColorStr = string.format("%02X%02X%02X", r,g,b)
	local hexcolor = tonumber(hexColorStr, 16)					 
	
	r = lh_toInt(self.lhLineColor.origin.x*255)
	g = lh_toInt(self.lhLineColor.origin.y*255);
	b = lh_toInt(self.lhLineColor.size.width*255);
	hexColorStr = string.format("%02X%02X%02X", r,g,b)
	local lineHexcolor = tonumber(hexColorStr, 16)					 
	
	
	local shape = nil;
	if(self.lhIsTile)then
		shape = Shape.new()
		shape:beginPath(Shape.NON_ZERO)
	
		shape:setLineStyle(4, lineHexcolor, 0)
		
		local imageFile = texDict:stringForKey("ImageFile");
		if(imageFile ~= "No Image")then
		
			local texture = Texture.new(imageFileWithFolder(imageFile))
			--local matrix = Matrix.new(0.5, 0, 0, 0.5, 0, 0)
			shape:setFillStyle(Shape.TEXTURE, texture);
		else
			shape:setFillStyle(Shape.SOLID, hexcolor, self.lhOpacity);
		end
		
	end
	
	local firstPoint = true;
	
	local visible = self:isVisible();
	if true ==  visible then
	
		local curves = texDict:arrayForKey("Curves")	
		local MAX_STEPS = 25;

		for i= 1, curves:count() do
			local currentCurve = curves[i];

			local curve = curves:dictAtIndex(i)
			local endCtrlPt   = curve:pointForKey("EndControlPoint")
			local startCtrlPt = curve:pointForKey("StartControlPoint")
			local endPt	   = curve:pointForKey("EndPoint")
			local startPt	 = curve:pointForKey("StartPoint")

			if( false == self.lhIsLine) then
			
				local prevPoint = {};
				local firstPt = true;
				
					
				local t = 0.0
				while ( t >= 0.0 and  t <= 1 + (1.0 / MAX_STEPS) ) do
					
					local vPoint = pointOnCurve(startPt, startCtrlPt, 
												endCtrlPt, endPt, t)

					if(false == firstPt)then
					
						local point1 = {x = prevPoint.x*convert.x, 
										y = prevPoint.y*convert.y};
						local point2 = {x = vPoint.x*convert.x,
										y = vPoint.y*convert.y};
					
						self:createLineShape(point1, point2, self.lhLineColor);
						
						if(firstPoint == true)then
							if(shape ~= nil)then
								shape:moveTo(point1.x, point1.y);
							end
							firstPoint = false;
						end
						if(shape ~= nil)then
							shape:lineTo(point2.x, point2.y);
						end
				
				
					end
					prevPoint = vPoint
					firstPt = false;

					t = t + 1.0 / MAX_STEPS
				end
			else
			
				local pos1 = {x = startPt.x*convert.x,
							  y = startPt.y*convert.y};
				local pos2 = {x = endPt.x*convert.x,
							  y = endPt.y*convert.y};
							  
				self:createLineShape(pos1, pos2, self.lhLineColor);
				if(firstPoint == true)then
					if(shape ~= nil)then
						shape:moveTo(pos1.x, pos1.y);
					end
					firstPoint = false;
				end
				if(shape ~= nil)then
					shape:lineTo(pos2.x, pos2.y);
				end
				
				
			end
		  end
	end
	
	if(shape ~= nil)then
		shape:closePath()
		shape:endPath()
		self:addChild(shape);
	end
	
end
--------------------------------------------------------------------------------
function LHBezier:constructPhysicObjectFromDictionary(bezierDict)

	self.b2World = LHSettings:sharedInstance().activeBox2dWorld 
	
	local propDict = bezierDict:dictForKey("TextureProperties");
	local physicsDict = bezierDict:dictForKey("PhysicsProperties")	


	local ptype = physicsDict:intForKey("Type")
	if( 3 == ptype)then --no physics - dont create bodies
		return
	end
	local physicType = b2.STATIC_BODY;
	if(ptype == 1)then
		physicType = b2.KINEMATIC_BODY;
	elseif(ptype == 2)then
		physicType = b2.DYNAMIC_BODY;
	end
	
	--print("phy type is " .. (physicType) .. " -> " .. (ptype));
	
	self.body = self.b2World:createBody{type = physicType, position = {x = 0, y = 0}}	
	self.body:setAngle(0.01745329252*self:getRotation());
	self.body.lhBezier = self;
	
	local convert = {x = 1.0, y = 1.0};
	
	local sdensity		 = physicsDict:floatForKey("Density");
	local sfriction	 = physicsDict:floatForKey("Friction");
	local srestitution	 = physicsDict:floatForKey("Restitution")
		
	local collisionFilter = {	 categoryBits = physicsDict:intForKey("Category"), 
								maskBits	  = physicsDict:intForKey("Mask"), 
								groupIndex	  = physicsDict:intForKey("Group") } 

	local currentShape = {}
		
	local tileVerts = physicsDict:objectForKey("TileVertices")
	if(tileVerts and tileVerts:arrayValue():count() > 0 )then
		local fixtures = physicsDict:arrayForKey("TileVertices");
		if(nil ~= fixtures) then
			
			for i = 1, fixtures:count() do
			
				local triangle = fixtures:arrayAtIndex(i);
			
				for j = 1, triangle:count() do	
				
					local point = triangle:pointAtIndex(j);
					currentShape[#currentShape+1] = point.x
					currentShape[#currentShape+1] = point.y
		
				end
				
				triangle = nil;
			
				local shape = b2.PolygonShape.new()
				shape:set(unpack(currentShape));
			
				local fix = self.body:createFixture{shape = shape, density = fdensity, restitution = frestitution, friction = ffriction}
				fix:setSensor(physicsDict:boolForKey("IsSensor"));
			
				currentShape = nil
				currentShape = {}
				
			end
			
			return
		end
	   end
		
	local curves = propDict:arrayForKey("Curves")
	local MAX_STEPS = 25;

	local finalBodyShape = {}
	local currentFixInfo;
	local currentShape = {}
	
	local firstPoint = true;
	for i= 1, curves:count() do
		
		local curve = curves:dictAtIndex(i)
		local endCtrlPt   = curve:pointForKey("EndControlPoint")
		local startCtrlPt = curve:pointForKey("StartControlPoint")
		local endPt	   = curve:pointForKey("EndPoint")
		local startPt	 = curve:pointForKey("StartPoint")
  
		  if false == self.lhIsLine then
			  
			  local prevPoint
			local firstPt = true
			
			local t = 0.0
			while ( t >= 0.0 and  t <= 1 + (1.0 / MAX_STEPS) ) do
				local vPoint = pointOnCurve(startPt, startCtrlPt, endCtrlPt, endPt, t)
							
				if false == firstPt then

					if(firstPoint == true)then
						currentShape[#currentShape+1] = prevPoint.x*convert.x
						currentShape[#currentShape+1] = prevPoint.y*convert.y
						firstPoint = false;
					end
					 currentShape[#currentShape+1] = vPoint.x*convert.x
					 currentShape[#currentShape+1] = vPoint.y*convert.y
											  
				end
				
				prevPoint = vPoint;
				firstPt = false;
		
				t = t + 1.0 / MAX_STEPS
			end
			

		  else
		  
			if(firstPoint == true)then
				currentShape[#currentShape+1] = startPt.x*convert.x
				currentShape[#currentShape+1] = startPt.y*convert.y
				firstPoint = false;
			end
			currentShape[#currentShape+1] = endPt.x*convert.x
			currentShape[#currentShape+1] = endPt.y*convert.y
										  
		  end						 
	end
	
	
	
	local chainShape = b2.ChainShape.new()
	chainShape:createChain(unpack(currentShape));
	local fix = self.body:createFixture{shape = chainShape, density = fdensity, restitution = frestitution, friction = ffriction}
	fix:setSensor(physicsDict:boolForKey("IsSensor"));
	fix:setFilterData(collisionFilter);
	
	self.body.fixedRotation = physicsDict:boolForKey("IsSensor");
					 
end
--------------------------------------------------------------------------------
function LHBezier:setUserClassProperties(spriteInfo)

	local classInfo = spriteInfo:dictForKey("CustomClassInfo");

	if(nil == classInfo)then
		return
	end
	
	self.lhClassName = classInfo:stringForKey("ClassName");
	
	if(self.lhClassName == nil)then
		return
	end
	
	require("LevelHelper.CustomClasses.LHCustomClasses");
	self.lhUserCustomInfo = lh_customClassInstanceWithName(self.lhClassName);

	if(self.lhUserCustomInfo == nil)then
		return
	end
	
	local classRep = classInfo:dictForKey("ClassRepresentation");
	
	self.lhUserCustomInfo:setPropertiesFromDictionary(classRep);
end
--------------------------------------------------------------------------------